home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-17 | 9.2 KB | 333 lines | [TEXT/PJMM] |
- program SolidModel;
-
- uses
- Matrix, Transformations, OffscreenCore, GrafSysCore, GrafSysScreen, GrafSysObject, Resources, OffScreenGraphics, GrafSysC;
-
- {This program demonstrates a sample implementation of the painter's algorithm }
- {with back-face removal and full triangle filling }
-
- const
- cMaxPoly = 100;
- maxDepth = 2000;
- minDepth = 0;
- cTheWindow = 400;
- degrees = 0.01745329; (* π/180 *)
-
- type
-
- trigon = record
- p: array[1..3] of integer;
- deepz: real;
- shallowz: real;
- color: integer;
- end;
-
- screenTrigon = record
- p: array[1..3] of point;
- deepz: real;
- shallowz: real;
- color: integer;
- end;
-
- Tsurfaces = array[1..cMaxPoly] of trigon;
-
- TSolid3D = object(TSGenericObject3D)
- numSurfaces: integer;
- surfaces: Tsurfaces;
- procedure init;
- override;
- procedure addPoly (p1, p2, p3: integer; color: integer);
- procedure draw;
- override;
- end;
-
- var
- screenBuf: array[1..cMaxPoly] of screenTrigon;
- screenBufNum: integer;
-
- procedure TSolid3D.init;
- override;
- begin
- inherited init;
- numsurfaces := 0;
- end;
-
- procedure TSolid3D.addPoly (p1, p2, p3: integer; color: integer);
-
- var
- thePoly: trigon;
-
- begin
- if numSurfaces < cMaxPoly then
- begin
- numSurfaces := numSurfaces + 1;
- thePoly.p[1] := p1;
- thePoly.p[2] := p2;
- thePoly.p[3] := p3;
- thePoly.deepZ := -1;
- thePoly.color := color;
- surfaces[numSurfaces] := thePoly;
- end;
- end;
-
- procedure TSolid3D.draw;
- override;
-
- var
- i, k: integer;
- h, v: integer;
- thePoint: Vector4;
- x, y, z: Real;
- zbyd: Real;
- index: integer;
- buffer, offset: integer;
- tempTrigon: screenTrigon;
- l, m: integer;
- thePlane: array[1..3] of Vector4;
-
- begin
- Transform2(FALSE); (* transform and gather bounds data *)
- InsetRect(oldBounds, -2, -2);
- EraseRect(oldBounds);
- (* now build the buffer for sorting triangles *)
- screenBufNum := 0; (* no triangles to draw *)
- for i := 1 to numSurfaces do
- begin
- tempTrigon.deepz := -1;
- tempTrigon.color := surfaces[i].color;
- for k := 1 to 3 do
- begin
- {get points and store them in triangle struct }
- index := surfaces[i].p[k];
- self.GenIndex(index - 1, buffer, offset);
- thePoint := theBufs[buffer]^[offset].transformed;
- {apply eye trafo as in ToScreen }
- {if current3DPort^.useEye then}
- {thePoint := VMult(thePoint, current3DPort^.MasterTransform); (* transform point so we can project *)
- {GetVector4(thePoint, x, y, z); (* return to real *)
-
- thePlane[k] := thePoint;
- h := theBufs[buffer]^[offset].screenx;
- v := theBufs[buffer]^[offset].screeny;
- z := thePoint[3]; (* danger! direct access to data structure *)
-
- {if current3DPort^.projection = parallel then {}
- {begin {}
- {h := Trunc(x) + current3DPort^.center.h; {}
- {v := -Trunc(y) + current3DPort^.center.v {}
- {end {}
- {else {}
- {begin {}
- {zbyd := 1 / (z / current3DPort^.d + 1);{}
- {h := Trunc(x * zbyd) + current3DPort^.center.h; (* do perspective transformation *)
- {v := -Trunc(y * zbyd) + current3DPort^.center.v;{}
- {end;{}
-
- {save screen positions }
- tempTrigon.p[k].h := h;
- tempTrigon.p[k].v := v;
- {check for new deepz}
- if z > tempTrigon.deepz then
- tempTrigon.deepz := z;
-
- end; (* for k *)
-
- {now insert the tempTrigon at the correct place in the screen trigon. Simple insertion sort }
- if (tempTrigon.deepz > 0) and IsVisible(thePlane[1], thePlane[2], thePlane[3]) then
- begin (* we must insert. otherwise z<0 : don't draw *)
- k := 1;
- while (k <= screenBufNum) and (tempTrigon.deepZ < screenBuf[k].deepz) do
- k := k + 1;
-
- (* now k points to the place we have to insert it or to the end of the buffer *)
- if k <= screenBufNum then
- begin (* we must move all polys up one to make space *)
- for l := screenBufNum downto k do
- screenBuf[l + 1] := screenBuf[l];
- end;
- screenBuf[k] := tempTrigon;
- screenBufNum := screenBufNum + 1;
- end;
- end; (* for i *)
-
- { now all triangles are sorted by ascending z values. draw them }
- i := 1;
- while i <= screenBufNum do
- begin
- tempTrigon := screenBuf[i];
- FillTriangle(tempTrigon.p[1], tempTrigon.p[2], tempTrigon.p[3], tempTrigon.Color, FALSE); {tempTrigon.Color}
- i := i + 1;
- end;
- end;
-
- procedure BuildObject (var Obj: TSolid3D);
-
- var
- OK: longint;
- theGreen: RGBColor;
- dummyBool: boolean;
-
- begin
-
- OK := Obj.AddPoint(100, 100.0, -100); (* 1 *)
- OK := Obj.AddPoint(-100, 100.0, -100);
- OK := Obj.AddPoint(-100, -100.0, -100);
- OK := Obj.AddPoint(100, -100.0, -100);
-
- OK := Obj.AddPoint(100, 100.0, 100); (* 5 *)
- OK := Obj.AddPoint(-100, 100.0, 100);
- OK := Obj.AddPoint(-100, -100.0, 100);
- OK := Obj.AddPoint(100, -100.0, 100);
-
- Obj.addPoly(1, 2, 3, 16); (* top *)
- Obj.addPoly(3, 4, 1, 16);
-
- obj.addPoly(7, 6, 5, 32); (* bottom *)
- obj.addPoly(5, 8, 7, 32);
-
- obj.addPoly(1, 5, 6, 48); (* left *)
- obj.addPoly(6, 2, 1, 48);
-
- obj.addpoly(8, 4, 3, 128); (* right *)
- obj.addPoly(3, 7, 8, 128);
-
- obj.addpoly(1, 4, 8, 144); (* front *)
- obj.addpoly(8, 5, 1, 144);
-
- obj.addPoly(7, 3, 2, 200); (* back *)
- obj.addPoly(2, 6, 7, 200);
- end;
-
- procedure Check (theErr: integer);
- begin
- if theErr <> noErr then
- DebugStr(InterPretError(theErr));
- end;
-
- {MAIN PROGRAM}
-
- var
- theCube: TSolid3D;
- theCoords: TSObject3D;
- theFighter: TSObject3D;
- theShuttle: TSObject3D;
- EyeLoc: Vector4;
- theWindow: WindowPtr;
- dummyLong: longint;
- copyRect: Rect;
- time: longint;
- done: boolean;
- direction: integer;
- depth: integer;
-
- begin
- done := FALSE;
- direction := 10;
- depth := 0;
- InitCursor;
- InitGrafSys;
- theWindow := GetNew3DWindow(cTheWindow, pointer(-1));
- SetVector4(EyeLoc, 0, 0, -300);
- SetEyeChar(TRUE, EyeLoc, 0, 0, 0, 90 * degrees, fast);
- New(theCube);
- theCube.Init;
- BuildObject(theCube);
- theCube.Translate(0, 0, 0);
- { theCube.Draw;}
-
- (* now load the coord sys to animate left to the cube *)
- theCoords := GetNewNamedObject('XYZ Coord');
- theCoords.Translate(-300, 300, 0);
- theCoords.SetAutoerase(TRUE);
-
- (* now load the fighter to animate right of the cube *)
- theFighter := GetNewNamedObject('theFighter');
- theFighter.Translate(300, 300, 0);
- theFighter.SetAutoerase(TRUE);
-
- (* now load the space shuttle *)
- theShuttle := GetNewNamedObject('Shuttle');
- theShuttle.Scale(2, 2, 2);{}
- theShuttle.Translate(0, -130, 0);
- theShuttle.SetAutoerase(TRUE);
-
- (* Now Add legend to window *)
- MoveTo(theWindow^.portRect.left + 10, theWindow^.portRect.bottom - 20);
- TextFont(Courier);
- TextSize(10);
- DrawString('Press Mousebutton to halt,');
- MoveTo(theWindow^.portRect.left + 10, theWindow^.portRect.bottom - 10);
- DrawString('doubleclick to exit');
-
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 180);
- DrawString(' Animation Stats:');
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 170);
- DrawString(' ----------------');
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 160);
- DrawString(' Number of Objects : 4');
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 150);
- DrawString(' Number of Points : 97');
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 140);
- DrawString(' Number of Lines : 87');
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 130);
- DrawString(' Number of Surfaces: 12');
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 100);
- DrawString(' Animation: Full Off-Screen');
- MoveTo(theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 90);
- DrawString(' Buffering');
- SetRect(copyRect, theWindow^.portRect.right - 180, theWindow^.portRect.bottom - 190, theWindow^.portRect.right - 5, theWindow^.portRect.bottom - 80);
- FrameRect(copyRect);
- theCube.Draw;
- theCoords.Draw;
- theFighter.Draw;
- theShuttle.Draw;
- Check(AttachOffscreen(theWindow, pointer(-1))); (* does automatic sanity check *)
- repeat
- Check(BeginOSDraw(theWindow));
- theCube.Draw; (* erase it and redraw it*)
- theCoords.Draw;
- theFighter.Draw;
- theShuttle.Draw;
- Check(EndOSDraw(theWindow));
-
- UnionRect(theCube.oldBounds, theCube.bounds, copyrect);
- Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
- UnionRect(theCoords.oldBounds, theCoords.bounds, copyrect);
- Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
- UnionRect(theFighter.oldBounds, theFighter.bounds, copyrect);
- Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
- UnionRect(theShuttle.oldBounds, theShuttle.bounds, copyrect);
- Check(CopyOS2Screen(theWindow, copyrect, srcCopy));
-
- {Delay(1, dummyLong);{}
-
- theCube.Rotate(5 * degrees, 2 * degrees, 1 * degrees);
- theCube.Translate(0, 0, 3 * direction);
- theCoords.Rotate(2 * degrees, 5 * degrees, 1 * degrees);
- {theCoords.Translate(0, 0, 0 * direction);{}
- theFighter.Rotate(2 * degrees, 1 * degrees, 5 * degrees);
- {theFighter.Translate(0, 0, direction);{}
- theShuttle.Rotate(7 * degrees, 0 * degrees, 7 * degrees);
- {theShuttle.Translate(0, 0, direction);{}
-
- depth := depth + direction;
- if depth > maxdepth then
- direction := -direction;
- if depth <= minDepth then
- direction := -direction;
-
- if button then
- begin
- time := TickCount - time;
- if time < GetDblTime div 2 then
- done := true
- else
- repeat
- until not button;
- time := tickCount;
- end;
-
- until done;
- repeat
- until not button;
- end.